import { Rect as GRect, Text as GText, TextStyleProps } from "@antv/g";
import {
  Badge,
  CommonEvent,
  ExtensionCategory,
  Graph,
  GraphEvent,
  iconfont,
  Label,
  LabelStyleProps,
  NodeData,
  Rect,
  register,
  treeToGraphData,
} from "@antv/g6";
import { useCallback, useEffect, useRef } from "react";

type INDServer = {
  id: string;
  label: string;
  mark?: string;
  amt?: number;
  amtUnit?: string;
  amtPer?: number;
  amtPerText?: string;
  width?: number;
  height?: number;
  children?: INDServer[];
};

interface INodeData extends NodeData {
  data?: INDServer;
}

const COLORS = {
  B: "#1783FF",
  R: "#F46649",
  Y: "#DB9D0D",
  G: "#60C42D",
  DI: "#A7A7A7",
};
const GREY_COLOR = "#CED4D9";

type RectAttr = InstanceType<typeof Rect>["parsedAttributes"];
class TreeNode extends Rect {
  get data() {
    return this.context.model.getNodeLikeDatum(this.id) as INodeData;
  }

  get childrenData() {
    return this.context.model.getChildrenData(this.id);
  }

  getLabelStyle(attributes) {
    const [width, height] = this.getSize(attributes);

    return {
      x: -width / 2 + 8,
      y: -height / 2 + 16,
      text: this.data.data.label,
      fontSize: 12,
      opacity: 0.85,
      fill: "#000",
      cursor: "pointer",
    } as LabelStyleProps;
  }

  drawPriceShape(attributes, container) {
    const [width, height] = this.getSize(attributes);
    const priceStyle = {
      x: -width / 2 + 8,
      y: height / 2 - 8,
      text: this.data.data.amt + "",
      fontSize: 16,
      fill: "#000",
      opacity: 0.85,
    } as TextStyleProps;

    this.upsert("price", GText, priceStyle, container);
  }
  drawCurrencyShape(attributes, container) {
    const [, height] = this.getSize(attributes);

    const currencyStyle = {
      x: this.shapeMap["price"].getLocalBounds().max[0] + 4,
      y: height / 2 - 8,
      text: this.data.data.amtUnit || "万元",
      fontSize: 12,
      fill: "#000",
      opacity: 0.75,
    } as TextStyleProps;
    this.upsert("currency", GText, currencyStyle, container);
  }

  drawVariableShape(attributes, container) {
    const [width, height] = this.getSize(attributes);

    const variableStyle = {
      fill: "#000",
      fontSize: 12,
      opacity: 0.45,
      textAlign: "right",
      text: this.data.data.amtPerText,
      x: width / 2 - 4,
      y: -height / 2 + 24,
    } as TextStyleProps;
    this.upsert("variable", GText, variableStyle, container);
  }
  drawPercentShape(attributes, container) {
    const [width, height] = this.getSize(attributes);

    const percentStyle = {
      x: width / 2 - 4,
      y: -height / 2 + 38,
      text: this.data.data.amtPer && `${((Number(this.data.data.amtPer) || 0) * 100).toFixed(2)}%`,
      fontSize: 12,
      textAlign: "right",
      fill: COLORS["R"],
    } as TextStyleProps;
    this.upsert("percent", GText, percentStyle, container);
  }

  drawProcessBarShape(attributes: RectAttr, container) {
    const { amtPer: rate = 0 } = this.data.data;
    const { radius } = attributes;
    const color = COLORS["B"];
    const percent = `${Number(rate) * 100}%`;
    const [width, height] = this.getSize(attributes);
    const processBarStyle = {
      x: -width / 2,
      y: height / 2 - 4,
      width: width,
      height: 4,
      radius: [0, 0, radius, radius],
      fill: `linear-gradient(to right, ${color} ${percent}, ${GREY_COLOR} ${percent})`,
    };

    this.upsert("process-bar", GRect, processBarStyle, container);
  }

  drawCollapseShape(attributes, container) {
    if (this.childrenData.length === 0) return false;
    const { collapsed } = attributes;
    const [width, height] = this.getSize(attributes);

    const collapseStyle = {
      backgroundFill: "#fff",
      backgroundHeight: 16,
      backgroundLineWidth: 1,
      backgroundRadius: 0,
      backgroundStroke: GREY_COLOR,
      backgroundWidth: 16,
      cursor: "pointer",
      fill: GREY_COLOR,
      fontSize: 16,
      text: collapsed ? "+" : "-",
      textAlign: "center",
      textBaseline: "middle",
      x: width / 2,
      y: 0,
    } as InstanceType<typeof Badge>["attributes"];
    const btn = this.upsert("collapse", Badge, collapseStyle, container);

    if (btn && !Reflect.has(btn, "__bind__")) {
      Reflect.set(btn, "__bind__", true);
      btn.addEventListener(CommonEvent.CLICK, () => {
        const { collapsed } = this.attributes;
        const graph = this.context.graph;
        if (collapsed) graph.expandElement(this.id);
        else graph.collapseElement(this.id);
      });
    }
  }

  getKeyStyle(attributes) {
    const keyStyle = super.getKeyStyle(attributes);
    return {
      ...keyStyle,
      fill: "#fff",
      lineWidth: 1,
      stroke: GREY_COLOR,
    };
  }

  render(attributes = this.parsedAttributes, container) {
    super.render(attributes, container);

    this.drawPriceShape(attributes, container);
    this.drawCurrencyShape(attributes, container);
    this.drawPercentShape(attributes, container);
    this.drawVariableShape(attributes, container);
    this.drawProcessBarShape(attributes, container);
    // this.drawCollapseShape(attributes, container);
  }
}

register(ExtensionCategory.NODE, "ChartQFG1", TreeNode, true);

const ChartQfg1 = () => {
  const ref = useRef<HTMLDivElement & { graph?: Graph }>(null);

  const getData = useCallback(() => {
    const graph = ref.current.graph;
    const d1 = [
      {
        id: "d1",
        label: "财政资金总预算",
        mark: "指标",
        amt: 222322222.235,
        amtPer: 0.98,
        amtPerText: "预算下达率",
        children: [
          {
            id: "d2",
            label: "财政资金安排",
            mark: "下达",
            amt: 222322111.22,
            amtPer: 0.86,
            amtPerText: "预算执行率",
            children: [
              { id: "d3", label: "财政资金支付", amt: 168322111.22, children: [{ id: "d4", label: "财政总会计核算", amt: 168322111.22 }] },
            ],
          },
        ],
      },
    ] as INDServer[];

    const v = d1[0];
    graph.clear();
    const data = treeToGraphData(v, {
      getNodeData: (datum, depth) => {
        const { children, ...restDatum } = datum;
        return {
          id: restDatum.id,
          data: restDatum,
          style: undefined,
          children: children?.map((child) => child.id),
        };
      },
    });

    graph.setData(data);
    graph.once(GraphEvent.AFTER_RENDER, () => {
      graph.fitView();
    });
  }, []);

  useEffect(() => {
    const graph = new Graph({
      container: ref.current,
      background: "#F2F7FA",
      autoFit: "center",
      padding: 26,
      animation: false,
      behaviors: ["zoom-canvas", "drag-canvas"],
      // plugins: ["minimap", "fullscreen", "toolbar"],
      // plugins: ["fullscreen"],

      node: {
        type: "ChartQFG1",
        style: {
          size: [202, 60],
          ports: [{ placement: "left" }, { placement: "right" }],
          radius: 4,
        },
      },
      // node1: {
      //   type: "html",
      //   style: {
      //     size: [240, 80],
      //     innerHTML: (d: INodeData) => {
      //       const { data } = d;

      //       return `
      // <div
      //   style="
      //     width: 100%;
      //     height: 100%;
      //     border: 1px solid #000;
      //     user-select: none;
      //     display: flex;
      //     padding: 10px;
      //     background: #fff;
      //   "
      // >
      //   ${
      //     data.amtPerText
      //       ? `<div
      //     style="
      //       flex: none;
      //       position: relative;
      //       border: 3px solid #4bb2ff;
      //       width: 65px;
      //       height: 65px;
      //       text-align: center;
      //       border-radius: 50%;
      //     "
      //   >
      //     <div style="line-height: 65px">${data.amtPer * 100}%</div>
      //     <div
      //       style="
      //         position: absolute;
      //         bottom: -8px;
      //         height: 16px;
      //         font-size: 12px;
      //         background: #fff;
      //       "
      //     >
      //       ${data.amtPerText}
      //     </div>
      //   </div>`
      //       : ""
      //   }
      //   <div
      //     style="
      //       display: flex;
      //       flex-direction: column;
      //       justify-content: space-around;
      //       font-weight: 600;
      //     "
      //   >
      //     <div>${data.label}${data.mark ? `（${data.mark}）` : ""}</div>
      //     <div><span>${data.amt}</span><span>万元</span></div>
      //   </div>
      // </div>
      //       `;
      //     },
      //   },
      //   palette: {
      //     type: "group",
      //     field: "label",
      //   },
      // },

      edge: {
        type: "polyline",
        style: {
          endArrow: true,
          router: {
            // type: "orth",
          },
        },
      },
      layout: {
        type: "dagre",
        rankdir: "LR",
        align: "UL",
      },
    });
    ref.current.graph = graph;
    graph.render();

    getData();
  }, []);

  return (
    <>
      <h2>官方：图布局 Dagre </h2>
      全覆盖-1-财政资金跟踪
      <div ref={ref} style={{ width: "100%", minHeight: 600 }}></div>
    </>
  );
};

export default ChartQfg1;
